package com.grm.security.perms;

import com.alibaba.fastjson.JSON;
import com.grm.common.Result;
import com.grm.security.details.LoginUser;
import com.grm.util.JwtUtil;
import com.grm.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * 解决天坑坑坑坑坑----------------
 * 登录成功，一直401，显示匿名用户鉴权失败，
 * 是因为SecurityContextHolder自己把Context清楚了，我们需要重新设置一下
 *
 * @author gaorimao
 * @date 2022/02/10
 */
@Slf4j
@Component
public class MyOncePerRequestFilter extends OncePerRequestFilter {
    private static final List<String> IGNORE_URLS = Arrays.asList("/","/login","/ssh/check");

    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (!IGNORE_URLS.contains(request.getRequestURI())
                && !request.getRequestURI().contains("/webjars")
                && !request.getRequestURI().contains("/swagger-resources")
                && !request.getRequestURI().contains("/v3/api-docs")
                && !request.getRequestURI().contains("/swagger-ui")
                && !request.getRequestURI().contains("/doc.html")
        ) {
            log.info("[RequestURI] path = {}", request.getRequestURI());
            String token = request.getHeader("token");
            log.info("[RequestURI] token = {}", token);
            if (ObjectUtils.isEmpty(token)) {
                Result.renderJsonStr(response, Result.failed(500, "获取token失败！"));
            }
            String username = jwtUtil.parseToken(token);
            if (ObjectUtils.isEmpty(username)) {
                Result.renderJsonStr(response, Result.failed(500, "token解析失败！"));
            }
            Object redisTokenObj = redisUtil.get("token:" + username);
            if (redisTokenObj == null) {
                Result.renderJsonStr(response, Result.failed(500, "token已过期！"));
            }
            Object loginUserObj = redisUtil.get("LoginUser:" + username);
            if (loginUserObj == null) {
                Result.renderJsonStr(response, Result.failed(500, "获取当前登录用户失败！"));
            }
             //LoginUser loginUser = JSON.parseObject(JSON.toJSONString(loginUserObj),LoginUser.class);
            LoginUser loginUser = (LoginUser) loginUserObj;
            log.info("[LoginUser] redis loginUser = {}", JSON.toJSONString(loginUser));

            /*
                重新设置SecurityContextHolder
             */
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, loginUser.getPassword(), loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        filterChain.doFilter(request, response);
    }
}
